import json
import smtplib
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.utils import formataddr
import cv2
from cv2.typing import MatLike

from utils.funcs import get_developer_msg


class Notifier:
    def __init__(self):
        self.smtp_ssl = None
        self.service = None
        self.email = None
        self.password = None
        self.name = None
        self.login()

    def login(self):
        with open(r"data\settings.json", 'r', encoding='utf-8') as f:
            settings = json.load(f)['Notifier']
        self.smtp_ssl = settings['smtp_ssl']
        self.email = settings['email']
        self.password = settings['password']
        self.name = settings['name']
        self.service = smtplib.SMTP_SSL(self.smtp_ssl)
        try:
            self.service.login(self.email, self.password)
        except smtplib.SMTPAuthenticationError:
            # 可能是被禁止发送邮件了, 使用备用邮箱通知, 并给原邮箱发送通知
            self.email = settings['email2']
            self.password = settings['password2']
            self.name = settings['name2']
            self.service.login(self.email, self.password)
            self.send(*get_developer_msg("[smtplib.SMTPAuthenticationError] 账号被禁止发送邮件"), to=settings['email'])

    def send(self, subject: str, content: str, to: str | list[str], image: MatLike | bytes = None):
        """
        发送邮件
        :param subject: 标题
        :param content: 内容
        :param to: 目标邮箱
        :param image: 图片
        """
        msg = MIMEMultipart()
        # 添加标题
        msg['Subject'] = subject
        # 添加发送人和收件人
        msg['From'] = formataddr((self.name, self.email))
        # 添加内容
        msg.attach(MIMEText(content))
        if isinstance(to, str):
            msg['to'] = to
        elif isinstance(to, list):
            msg['to'] = ','.join(to)
        else:
            raise TypeError(f"[param]to: str | list[str] , got {type(to)}")
        if image is not None:
            # 添加图片附件
            if isinstance(image, MatLike):
                # cv格式先转为二进制
                _, buffer = cv2.imencode(".png", image)
                binary_data = buffer.tobytes()
            elif isinstance(image, bytes):
                binary_data = image
            else:
                raise TypeError(f"[param]image: MatLike | bytes , got {type(image)}")
            msg_image = MIMEImage(binary_data, "png")
            msg_image.add_header('Content-Disposition', 'attachment', filename="image.png")
            msg.attach(msg_image)
        self.service.sendmail(self.email, to, msg.as_string())

    def quit(self):
        self.service.quit()
